package com.listeningframework.boot.codegen.context;

import com.listeningframework.boot.codegen.exception.CodeGenException;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.plexus.util.FileUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * CodeGen Context
 */
public class Context {

    private static Context context = null;

    /**
     * 数据库连接Context
     */
    private ConnectionContext connectionContext;
    /**
     * 工程Context
     */
    private ProjectContext projectContext;
    /**
     * 模型Context
     */
    private ModuleContext moduleContext;

    private Context() {

    }

    public static void loadContext(String srcLocation, String configLocation) throws CodeGenException {
        Context context = new Context();
        context.init(srcLocation, configLocation);
        context.getModuleContext().afterProperties();
    }

    private void init(String srcLocation, String configLocation) throws CodeGenException {
        try {
            if (context != null) {
                return;
            }
            File configFile = new File(srcLocation + configLocation + "config.xml");
            if (configFile == null || !configFile.exists()) {
                throw new CodeGenException("Config File Not Exists");
            }
            String content = FileUtils.fileRead(configFile, "utf-8");
            Document document = DocumentHelper.parseText(content);
            if (document == null) {
                throw new RuntimeException("document is null");
            }
            Element root = document.getRootElement();
            if (root == null) {
                throw new CodeGenException("配置文件节点[configuration]不正确");
            }
            Element connectionElement = root.element("connection");
            if (connectionElement == null) {
                throw new CodeGenException("数据库连接信息缺失");
            }
            String platform = connectionElement.attributeValue("platform"); // 数据库类型
            String host = connectionElement.attributeValue("host"); // Host
            String port = connectionElement.attributeValue("port");// 端口
            String database = connectionElement.attributeValue("database"); // 数据库
            String username = connectionElement.attributeValue("username");// 账号
            String password = connectionElement.attributeValue("password"); // 密码
            if (StringUtils.isAnyBlank(platform, host, port, database, username, password)) {
                throw new CodeGenException("数据库连接属性缺失");
            }
            ConnectionContext connectionContext = new ConnectionContext();
            connectionContext.setPlatform(platform);
            connectionContext.setHost(host);
            connectionContext.setPort(port);
            connectionContext.setDatabase(database);
            connectionContext.setUsername(username);
            connectionContext.setPassword(password);
            this.connectionContext = connectionContext;

            // Project节点信息
            Element projectElement = root.element("project");
            String projectPackage = projectElement.attributeValue("package"); // 工程包
            String controller = projectElement.attributeValue("web"); // controller包
            String entity = projectElement.attributeValue("entity"); // entity包
            String service = projectElement.attributeValue("service"); // service包
            String domain = projectElement.attributeValue("domain"); // domain包
            String dao = projectElement.attributeValue("dao"); // dao包
            String mybatis = projectElement.attributeValue("mybatis"); // mybatis脚本路径
            if (StringUtils.isBlank(projectPackage)) {
                throw new CodeGenException("系统包缺失");
            }
            ProjectContext projectContext = new ProjectContext();
            projectContext.setSrcLocation(srcLocation);
            projectContext.setProjectPackage(projectPackage);
            projectContext.setWebPackage(StringUtils.isBlank(controller) ? "web" : controller);
            projectContext.setServicePackage(StringUtils.isBlank(service) ? "service" : service);
            projectContext.setDomainPackage(StringUtils.isBlank(domain) ? "domain" : domain);
            projectContext.setEntityPackage(StringUtils.isBlank(entity) ? "entity" : entity);
            projectContext.setDaoPackage(StringUtils.isBlank(dao) ? "repository" : dao);
            projectContext.setMybatisLocation(StringUtils.isBlank(mybatis) ? "spring/mybatis/" : mybatis);
            projectContext.setConfigLocation(configLocation);
            this.projectContext = projectContext;

            // Modules 节点
            Element moduleElement = root.element("modules");
            String enabled = moduleElement.attributeValue("enabled"); // 是否可用
            String orm = moduleElement.attributeValue("orm"); // ORM
            String readFromDB = moduleElement.attributeValue("read-from-db");// 是否读取数据库
            String generate = moduleElement.attributeValue("generate");// 是否生成文件
            if (StringUtils.isBlank(orm) && !Arrays.asList("JPA", "MYBATIS").contains(StringUtils.upperCase(orm))) {
                throw new CodeGenException("ORM参数不正确");
            }
            ModuleContext moduleContext = new ModuleContext();
            moduleContext.setEnabled(StringUtils.equalsIgnoreCase(enabled, "true"));
            moduleContext.setOrm(StringUtils.upperCase(orm));
            moduleContext.setReadFromDB(StringUtils.equalsIgnoreCase(readFromDB, "true"));
            moduleContext.setGenerate(StringUtils.equalsIgnoreCase(generate, "true"));
            // Entity List
            @SuppressWarnings("unchecked")
            List<Element> entityList = moduleElement.elements("entity");
            if (entityList == null || entityList.isEmpty()) {
                this.moduleContext = moduleContext;
            }
            Iterator<Element> iterator = entityList.iterator();
            while (iterator.hasNext()) {
                Element entityElement = iterator.next();
                EntityContext entityContext = new EntityContext();
                // 基本信息
                String subPackage = entityElement.attributeValue("sub-package"); // 子包
                String table = entityElement.attributeValue("table"); // 表名
                String desc = entityElement.attributeValue("desc"); // 功能描述
                String entityprefix = entityElement.attributeValue("prefix"); // 模型前缀
                String entityEnabled = entityElement.attributeValue("enabled"); // 是否有效
                String entityOverride = entityElement.attributeValue("override"); // 是否覆盖
                if (StringUtils.isAnyBlank(table, desc, entityprefix)) {
                    throw new CodeGenException("Entity模型参数缺失");
                }
                entityContext.setSubPackage(subPackage);
                entityContext.setTable(table);
                entityContext.setPrefix(entityprefix);
                entityContext.setDesc(desc);
                entityContext.setEnabled(!StringUtils.equalsIgnoreCase(entityEnabled, "false"));
                entityContext.setOverride(!StringUtils.equalsIgnoreCase(entityOverride, "false"));

                // Controller
                String entityWithController = entityElement.attributeValue("with-controller"); // 是否生成Controller
                String entityCustomControllerTpl = entityElement.attributeValue("is-custom-controller-template"); // 是否自定义Controller模板
                String entityCustomControllerTplName = entityElement.attributeValue("custom-controller-template-name"); // 自定义Controller模板名称
                boolean isCustomControllerTpl = StringUtils.equalsIgnoreCase(entityCustomControllerTpl, "true");
                if (isCustomControllerTpl && StringUtils.isBlank(entityCustomControllerTplName)) {
                    throw new CodeGenException("自定义Controller模板名称缺失");
                }
                entityContext.setWithController(!StringUtils.equalsIgnoreCase(entityWithController, "false"));
                entityContext.setCustomControllerTemplate(isCustomControllerTpl);
                entityContext.setCustomControllerTemplateName(entityCustomControllerTplName);

                // Service
                String entityWithService = entityElement.attributeValue("with-service"); // 是否生成Service
                String entityCustomServiceTpl = entityElement.attributeValue("is-custom-service-template"); // 是否自定义Service模板
                String entityCustomServiceTplName = entityElement.attributeValue("custom-service-template-name"); // 自定义Service模板名称
                boolean isCustomServiceTpl = StringUtils.equalsIgnoreCase(entityCustomServiceTpl, "true");
                if (isCustomServiceTpl && StringUtils.isBlank(entityCustomServiceTplName)) {
                    throw new CodeGenException("自定义Service模板名称缺失");
                }
                entityContext.setWithService(!StringUtils.equalsIgnoreCase(entityWithService, "false"));
                entityContext.setCustomServiceTemplate(isCustomServiceTpl);
                entityContext.setCustomServiceTemplateName(entityCustomServiceTplName);

                // Domain
                String entityWithDomain = entityElement.attributeValue("with-domain"); //是否生成Domain
                String entityCustomDomainTpl = entityElement.attributeValue("is-custom-domain-template"); // 是否自定义 domain模板
                String entityCustomDomainTplName = entityElement.attributeValue("custom-domain-template-name"); // 自定义 domain模板名称
                String withCreateInfo = entityElement.attributeValue("with-create-info"); // 生成创建信息
                boolean isCustomDomainTpl = StringUtils.equalsIgnoreCase(entityCustomDomainTpl, "true");
                if (isCustomDomainTpl && StringUtils.isBlank(entityCustomDomainTplName)) {
                    throw new CodeGenException("自定义Domain模板名称缺失");
                }
                entityContext.setWithDomain(!StringUtils.equalsIgnoreCase(entityWithDomain, "false"));
                entityContext.setCustomDomainTemplate(isCustomDomainTpl);
                entityContext.setCustomDomainTemplateName(entityCustomDomainTplName);

                // Entity
                String entityWithEntity = entityElement.attributeValue("with-entity"); // 是否生成Entity
                String entityCustomEntityTpl = entityElement.attributeValue("is-custom-entity-template"); // 是否自定义 entity 模板
                String entityCustomEntityTplName = entityElement.attributeValue("custom-entity-template-name"); // 自定义 entity 模板名称
                boolean isCustomEntityTpl = StringUtils.equalsIgnoreCase(entityCustomEntityTpl, "true");
                if (isCustomEntityTpl && StringUtils.isBlank(entityCustomEntityTplName)) {
                    throw new CodeGenException("自定义Entity模板名称缺失");
                }
                entityContext.setWithEntity(!StringUtils.equalsIgnoreCase(entityWithEntity, "false"));
                entityContext.setCustomEntityTemplate(isCustomEntityTpl);
                entityContext.setCustomEntityTemplateName(entityCustomEntityTplName);
                entityContext.setWithCreateInfo(StringUtils.equalsIgnoreCase(withCreateInfo, "true"));

                // DAO
                String entityWithMybatis = entityElement.attributeValue("with-mybatis"); // 是否生成MyBatis
                String entityWithDao = entityElement.attributeValue("with-dao"); // 是否生成DAO
                String entityCustomDaoTpl = entityElement.attributeValue("is-custom-dao-template"); // 是否自定义 DAO 模板
                String entityCustomDaoTplName = entityElement.attributeValue("custom-dao-template-name"); // 自定义 DAO 模板名称
                boolean isCustomDaoTpl = StringUtils.equalsIgnoreCase(entityCustomDaoTpl, "true");
                if (isCustomDaoTpl && StringUtils.isBlank(entityCustomDaoTplName)) {
                    throw new CodeGenException("自定义Entity模板名称缺失");
                }
                entityContext.setWithMybatis(!StringUtils.equalsIgnoreCase(entityWithMybatis, "false"));
                entityContext.setWithDao(!StringUtils.equalsIgnoreCase(entityWithDao, "false"));
                entityContext.setCustomDaoTemplate(isCustomDaoTpl);
                entityContext.setCustomDaoTemplateName(entityCustomDaoTplName);
                moduleContext.addEntity(entityContext);
            }
            this.moduleContext = moduleContext;
            Context.context = this;
        } catch (CodeGenException e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenException("Context初始化异常", e);
        }
    }

    public static Context getContext() {
        return context;
    }

    public ModuleContext getModuleContext() {
        return moduleContext;
    }

    public ProjectContext getProjectContext() {
        return projectContext;
    }

    public ConnectionContext getConnectionContext() {
        return connectionContext;
    }
}
